package com.gyj.aop;

import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.banksteel.workspace.constant.WorkSpaceConstant;
import com.banksteel.workspace.exception.IllegalParameterException;
import com.gyj.annotation.RedisLock;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Aspect
@Component
public class RedisLockAspect {
	@Resource
	private StringRedisTemplate stringRedisTemplate;

	@Pointcut("@annotation(com.banksteel.workspace.annotation.RedisLock)")
	public void redisLockPoint() {
	}

	@Around("redisLockPoint()")
	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
		// 1.前置方法记录参数
		RedisLock annotation = addOperationLog(joinPoint);
		// 2.分布式并发锁
		Object res = null;
		String clientId = UUID.randomUUID().toString();
		String lockKey = annotation.redisKey();
		try {
			Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS);
			if (!result) {
				throw new IllegalParameterException(WorkSpaceConstant.SYSTEM_BUSY_HINT);
			}
			// 执行方法
			res = joinPoint.proceed();
		} finally {
			if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
				stringRedisTemplate.delete(lockKey);
			}
		}
		return res;
	}

	private RedisLock addOperationLog(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		RedisLock annotation = signature.getMethod().getAnnotation(RedisLock.class);
		// 请求的方法名
		Method method = signature.getMethod();
		String methodName = signature.getName();
		// 请求的方法参数值
		Object[] args = joinPoint.getArgs();
		// 请求的方法参数名称
		LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
		String[] paramNames = u.getParameterNames(method);
		if (args != null && paramNames != null) {
			String params = joinPoint.getTarget().getClass().getName() + "." + methodName + "方法参数";
			for (int i = 0; i < args.length; i++) {
				params += "," + paramNames[i] + ":" + args[i];
			}
			log.info("记录日志:" + params);
		}
		return annotation;
	}
}